package edu.utexas.mapreduce;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.TreeMap;
import java.util.Vector;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.sun.org.apache.xerces.internal.parsers.SAXParser;

public class JobRequest {

	public static final String requestKey = "request";

	private Vector<Job> requests = new Vector<Job>();

	//For when job is to be programmaticaly configured
	public JobRequest (){
	}
	
	//For when job is to be read from a request XML file
	public JobRequest (File jobXMLFile) throws IOException, SAXException{
		if (!jobXMLFile.exists())
			throw new IOException("XML file not found");
		
		XMLReader myXMLReader = new SAXParser();
		//parse XML to map
		//String preURI = jobFile.getPath().replaceAll("\\s", "%20");
		JobContentHandler contentHandler = new JobContentHandler();	
		myXMLReader.setContentHandler(contentHandler);
		myXMLReader.parse(new InputSource(new FileInputStream(jobXMLFile)));
		fillRequests(contentHandler);
	}
	
	//For when job is described by an XML stream		
	public JobRequest (InputStream XMLStream) throws IOException, SAXException{
		XMLReader myXMLReader = new SAXParser();
		//parse XML to map
		JobContentHandler contentHandler = new JobContentHandler();	
		myXMLReader.setContentHandler(contentHandler);
		myXMLReader.parse(new InputSource(XMLStream));
		fillRequests(contentHandler);
	}

	public JobRequest (String XMLString) throws IOException, SAXException{
		XMLReader myXMLReader = new SAXParser();
		//parse XML to map
		JobContentHandler contentHandler = new JobContentHandler();	
		myXMLReader.setContentHandler(contentHandler);
		myXMLReader.parse(new InputSource(new StringReader(XMLString)));
		fillRequests(contentHandler);
	}
	
	
	private void fillRequests(JobContentHandler contentHandler){
		Vector<TreeMap<String,String>> jobs = contentHandler.getRequest();
		for (TreeMap<String,String> map: jobs)
			requests.add(new Job(map));
	}
	
	public boolean validate(){
		//validate that there is at least one job
		if (requests.isEmpty())
			return false;
		
		//validate all jobs within this request
		for(Job job:requests){
			if (!job.validate())
				return false;	
		}
		return true;
	}
	
	@Override
	public String toString(){
		StringWriter sw = new StringWriter();
		PrintWriter out = new PrintWriter(sw);
		//validate all jobs within this request
		for(int i=0;i<requests.size();i++){
			out.println("Job " + i);
			requests.elementAt(i).toString();
		}
		out.flush();
		sw.flush();
		return sw.toString();
	}
	
	public String toXMLString(boolean addHeader){
		// Write XML header and DTD		
		StringWriter sw = new StringWriter();
		PrintWriter out = new PrintWriter(sw);
		if (addHeader)
			out.println("<?xml version=\"1.0\" encoding=\"" + XML.ENCODING + "\"?>");
		out.println("<request>");
		for(int i=0;i<requests.size();i++)
			out.print(requests.elementAt(i).toXMLString(false));
		out.println("</request>");
		out.flush();		
		return sw.toString();
	}
	
	@Override
	public boolean equals(Object obj) {
		//check that they are the same type
		if (obj.getClass()!=this.getClass())
			return false;
		//check that they have the same number of jobs
		if(((JobRequest) obj).numberOfJobs() != this.requests.size())
			return false;
		//check that the jobs match
		int matches =0;
		for (Job ourJob: requests){
			for (Job theirJob: ((JobRequest) obj).getAllJobs()){
				if (ourJob.equals(theirJob)){
					matches++;
					break;
				}
			}
		}
		if (!(matches==requests.size()))
			return false;
		return true;
	}
	
	public int numberOfJobs(){
		return requests.size();
	}
	
	public Vector<Job> getAllJobs(){
		return requests;
	}
	
	public Job getJob(int id){
		return requests.elementAt(id);
	}

	public int getJob(String name){
		return requests.size();
	}
}
	

